package com.z;


public class CodeWriter {


    final String[] types = {"add", "sub", "neg", "eq", "gt", "lt", "and", "or", "not"};
    final String[] arg2Arry = {"push", "pop", "function", "call"};

    String writeArithmetic(String command) {
        // 操作数为两个
        final String output1 = "@SP\r\n"
                + "AM=M-1\r\n"
                + "D=M\r\n"
                + "A=A-1\r\n";

        // 操作数为一个
        final String output2 = "@SP\r\n"
                + "A = M-1\r\n";

        String commandType = "";
        String output = "";

        for (String type : types) {

            if (command.contains(type)) {
                commandType = type;
            }
        }


        switch (commandType) {
            case "add":
                output = output1 + "M=M+D\r\n";
                break;
            case "sub":
                output = output1 + "M=D-M\r\n";
                break;
            case "neg":
                output = output2 + "M=-M\r\n";
                break;
            case "and":
                output = output1 + "M=D&M\r\n";
                break;
            case "or":
                output = output1 + "M=M|D\r\n";
                break;
            case "not":
                output = output2 + "M=!M\r\n";
                break;
            case "eq":
                output = createJudgementString("JEQ", 1);
                break;
            case "gt":
                output = createJudgementString("JGT", 2);
                break;
            case "lt":
                output = createJudgementString("JLT", 3);

        }

        return output;

    }

    // 编写push或者pop操作命令
    public String writePushPop(String command,String type, String fileName){
        String v1 = arg1(command,type).toUpperCase();
        String i = arg2(command,type);

        return processSegment(v1,i,type,fileName);

    }


    // 在实验7中用于决策对那个段进行操做
    String arg1(String command, String type) {

        if (type.matches("aritch")) {
            return command;
        } else {
            String[] s = command.split(" ");
            return s[1];
        }
    }

    // 在实验7中用于
     String arg2(String command, String type) {
        String output = "";
         for (String s : arg2Arry) {
             if (type.matches(s)) {
                 String[] s1 = command.split(" ");
                 output = s1[2];

             }
         }

         return output;

    }

    String createJudgementString(String judge, int index) {

        return "@SP\n" +
                "AM=M-1\n" +
                "D=M\n" +
                "A=A-1\n" +
                "D=M-D\n" +
                "@TRUE + index\n" +
                "D;" + judge + "\n" +
                "@FALSE" + index + "\n" +
                "(FALSE" + index + ")\n" +
                "@SP\n" +
                "A=A-1\n" +
                "M=0\n" +
                "(TRUE" + index + ")\n" +
                "@SP\n" +
                "A=A-1\n" +
                "M=-1";
    }

    /*
     * v1 表示对哪一个段进行操纵，即获得基地址
     * i 是偏移地址
     * type 表示要进行的操作类型
     * */
    String processSegment(String v1, String i, String type, String filename) {
        String output = "";
        String str = "";
        switch (v1) {
            case "CONSTANT":
                output = "@" + i + "\n" +
                        "D=A\n" +
                        "@SP\n" +
                        "A=M\n" +
                        "M=D\n" +
                        "@SP\n" +
                        "M=M+1\n";
                break;
            case "STATIC":
                if (type.matches("pop")) {
                    output = "@SP\r\n"
                            + "AM=M-1\r\n"
                            + "D=M\r\n"
                            + "@" + filename + "." + i + "\r\n"
                            + "M=D\r\n";
                } else {

                    output = "@" + filename + "." + i + "\r\n"
                            + "D=M\r\n"
                            + "@SP\r\n"
                            + "A=M\r\n"
                            + "M=D\r\n"
                            + "@SP\r\n"
                            + "M=M+1\r\n";
                }
            case"TEMP":
                if(type.matches("push")){
                    // 与其他的段相比，temp没有一个固定的线段指针保存基地址，tem段默认基地址就在5
                    output="@R5\n" +
                            "D=A\n" +
                            "@i\n" +
                            "D=A+D\t\n" +
                            "A=D\n" +
                            "D=M\n" +
                            "@SP\n" +
                            "A=M\n" +
                            "M=D\n" +
                            "@SP\n" +
                            "M=M+1\n";
                }else {
                     // pop temp i
                     // 弹出一个值，将其存入tem段的第i位置
                    output="\n" +
                            "@R5\n" +
                            "D=A\n" +
                            "@i\n" +
                            "D=A+D\t// 得到段地址\n" +
                            "@R13\n" +
                            "M=D\t\t// 存储段地址\n" +
                            "\n" +
                            "@SP\n" +
                            "AM=M-1\n" +
                            "D=M\t\t// 弹出stack中的值\n" +
                            "\n" +
                            "@R13\n" +
                            "A=M\n" +
                            "M=D";


                }

            case "POINTER":
                // 只有两个整数对POINTER是有效的,0:this,1:that
                // push pointer 0/1
                if(i.matches("0")){
                    i="this";
                }else {
                    i="that";
                }

                if (type.matches("push")) {
                    output = "@" + i + "\r\n"
                            + "D=M\n" +
                            "@SP\n" +
                            "A=M\n" +
                            "M=D\n" +
                            "@SP\n" +
                            "M=M+1";
                } else {
                    output="@SP\r\n"
                            +"AM=M-1\r\n"
                            +"D=M\r\n"
                            +"@"+i +"\r\n";
                }


            default:
                if (v1.matches("LOCAL")) {
                    // 拿到基地址
                    str = "@LCL\r\n";
                } else if (v1.matches("ARGUMENT")) {

                    str = "@ARG\r\n";
                } else {
                    str = "@" + v1 + "\r\n";
                }

                if (type.matches("push")) {
                    output = pushTemplate(str, i, true);
                } else {
                    output = popTemplate(str, i, true);
                }


        }

        return output;

    }

    String pushTemplate(String str, String i, boolean flag) {
        String str1 = flag ? "D=M\r\n" : "D=A\r\n";
        String output = str + str1
                // 使用A指令获得偏移量
                + "@" + i + "\r\n"
                + "A=D+A\r\n"
                + "D=M\r\n"
                + "@SP\r\n"
                + "A=M\r\n"
                + "M=D\r\n"
                + "@SP\r\n"
                + "M=M+1\r\n";
        return output;
    }

    String popTemplate(String str, String i, boolean flag) {
        // 1.取得了段的基地址
        String str1 = flag ? "D=M\r\n" : "D=A\r\n";
        String output = str + str1
                + "@" + i + "\r\n"    // 拿到偏移量
                + "D=A+D\r\n"
                + "@R13\r\n"
                + "M=D\r\n"
                + "@SP\r\n"
                + "AM=M-1\r\n"
                + "D=M\r\n"
                + "@R13\r\n"
                + "A=M\r\n"
                + "M=D\r\n";


        return output;

    }


}
